//-----------------------------------------------------------------------------
// MenuItem.cs
//
// Portions of this file
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.ComponentModel;

namespace HumanElement.Xna.Construct.GameState
{
    /// <summary>
    /// Helper class represents a single entry in a MenuScreen. By default this
    /// just draws the entry text string, but it can be customized to display menu
    /// entries in different ways. This also provides an event that will be raised
    /// when the menu entry is selected.
    /// </summary>
    [DefaultEvent("Selected")]
    [ToolboxItemFilter("Ferpect.GameState.MenuItem", ToolboxItemFilterType.Allow)]
    public abstract class MenuItem : Component
    {
        /// <summary>
        /// Tracks a fading focus effect on the entry.
        /// </summary>
        /// <remarks>
        /// The entries transition out of the focus effect when they lose focus.
        /// </remarks>
        private float focusFade;
        private bool hasFocus;
        private MenuScreen parentMenu;
        private Rectangle clientRect;

        public MenuItem()
        {
        }

        public virtual bool HitTest(Point pt)
        {
            return this.clientRect.Contains(pt);
        }

        [Category("Focus")]
        public event EventHandler<EventArgs> Enter;

        [Category("Focus")]
        public event EventHandler<EventArgs> Leave;

        [Category("Action")]
        public event EventHandler<EventArgs> Selected;

        [Browsable(false)]
        public MenuScreen Parent
        {
            get { return this.parentMenu; }
            set { this.parentMenu = value; }
        }

        /// <summary>
        /// Gets or sets the text of this menu entry.
        /// </summary>
        public abstract string GetText();

        /// <summary>
        /// Method for raising the Selected event.
        /// </summary>
        protected internal virtual void OnSelected()
        {
            if (this.Selected != null)
                this.Selected(this, EventArgs.Empty);
        }

        protected internal virtual void OnEnter()
        {
            this.hasFocus = true;
            if (this.Enter != null)
            {
                this.Enter(this, EventArgs.Empty);
            }
        }

        protected internal virtual void OnLeave()
        {
            this.hasFocus = false;
            if (this.Leave != null)
            {
                this.Leave(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// Updates the menu entry.
        /// </summary>
        public virtual void Update(MenuScreen screen, bool isActive, GameTime gameTime)
        {
            // When the menu selection changes, entries gradually fade between
            // their selected and deselected appearance, rather than instantly
            // popping to the new state.
            float fadeSpeed = (float)gameTime.ElapsedGameTime.TotalSeconds * 4;

            if (isActive && this.hasFocus)
                focusFade = Math.Min(focusFade + fadeSpeed, 1);
            else
                focusFade = Math.Max(focusFade - fadeSpeed, 0);
        }

        /// <summary>
        /// Draws the menu entry. This can be overridden to customize the appearance.
        /// </summary>
        public virtual void Draw(Vector2 position, bool isActive, GameTime gameTime)
        {
            // Draw the selected entry in yellow, otherwise white.
            Color color = (isActive && this.hasFocus) ? this.parentMenu.FocusTextColor : this.parentMenu.TextColor;

            // Pulsate the size of the selected menu entry.
            double time = gameTime.TotalGameTime.TotalSeconds;

            float pulsate = (float)Math.Sin(time * 6) + 1;

            float scale = 1 + pulsate * 0.05f * focusFade;

            // Modify the alpha to fade text out during transitions.
            color = new Color(color.R, color.G, color.B, this.parentMenu.TransitionAlpha);

            // Draw text, centered on the middle of each line.
            ScreenManager screenManager = this.parentMenu.ScreenManager;
            SpriteBatch spriteBatch = screenManager.SpriteBatch;
            SpriteFont font = this.parentMenu.Font;

            string text = this.GetText();

            Vector2 origin = new Vector2(0, font.LineSpacing / 2);

            spriteBatch.DrawString(font, text, position, color, 0, origin, scale, SpriteEffects.None, 0);

            Vector2 stringSize = font.MeasureString(text);
            this.clientRect = new Rectangle((int)(position.X - origin.X), (int)(position.Y - origin.Y), (int)stringSize.X, (int)stringSize.Y);
        }

        /// <summary>
        /// Queries how much space this menu entry requires.
        /// </summary>
        public virtual int GetHeight(MenuScreen screen)
        {
            return screen.Font.LineSpacing;
        }
    }
}
